
#include "nvme_internal.h"

struct nvme_quirk {
	struct pci_id	id;
	unsigned int	flags;
};

static const struct nvme_quirk nvme_quirks[] = {
	{
		{ NVME_PCI_VID_INTEL, 0x0953, NVME_PCI_VID_INTEL, 0x3702 },
		NVME_INTEL_QUIRK_READ_LATENCY | NVME_INTEL_QUIRK_WRITE_LATENCY
	},
	{
		{ NVME_PCI_VID_INTEL, 0x0953, NVME_PCI_VID_INTEL, 0x3703 },
		NVME_INTEL_QUIRK_READ_LATENCY | NVME_INTEL_QUIRK_WRITE_LATENCY
	},
	{
		{ NVME_PCI_VID_INTEL, 0x0953, NVME_PCI_VID_INTEL, 0x3704 },
		NVME_INTEL_QUIRK_READ_LATENCY | NVME_INTEL_QUIRK_WRITE_LATENCY
	},
	{
		{ NVME_PCI_VID_INTEL, 0x0953, NVME_PCI_VID_INTEL, 0x3705 },
		NVME_INTEL_QUIRK_READ_LATENCY | NVME_INTEL_QUIRK_WRITE_LATENCY
	},
	{
		{ NVME_PCI_VID_INTEL, 0x0953, NVME_PCI_VID_INTEL, 0x3709 },
		NVME_INTEL_QUIRK_READ_LATENCY | NVME_INTEL_QUIRK_WRITE_LATENCY
	},
	{
		{ NVME_PCI_VID_INTEL, 0x0953, NVME_PCI_VID_INTEL, 0x370a },
		NVME_INTEL_QUIRK_READ_LATENCY | NVME_INTEL_QUIRK_WRITE_LATENCY
	},
	{
		{ NVME_PCI_VID_MEMBLAZE, 0x0540, NVME_PCI_ANY_ID, NVME_PCI_ANY_ID },
		NVME_QUIRK_DELAY_BEFORE_CHK_RDY
	},
	{
		{ NVME_PCI_VID_INTEL, 0x0953, NVME_PCI_VID_INTEL, 0x370d },
		NVME_QUIRK_DELAY_AFTER_RDY
	},
	{
		{ 0x0000, 0x0000, 0x0000, 0x0000 },
		0
	}
};

/*
 * Compare each field. NVME_PCI_ANY_ID in s1 matches everything.
 */
static bool nvme_quirks_pci_id_match(const struct pci_id *id,
				     struct pci_device *pdev)
{
	if ((id->vendor_id == NVME_PCI_ANY_ID ||
	     id->vendor_id == pdev->vendor_id) &&
	    (id->device_id == NVME_PCI_ANY_ID ||
	     id->device_id == pdev->device_id) &&
	    (id->subvendor_id == NVME_PCI_ANY_ID ||
	     id->subvendor_id == pdev->subvendor_id) &&
	    (id->subdevice_id == NVME_PCI_ANY_ID ||
	     id->subdevice_id == pdev->subdevice_id))
		return true;

	return false;
}

unsigned int nvme_ctrlr_get_quirks(struct pci_device *pdev)
{
	const struct nvme_quirk *quirk = nvme_quirks;

	while (quirk->id.vendor_id) {
		if (nvme_quirks_pci_id_match(&quirk->id, pdev))
			return quirk->flags;
		quirk++;
	}

	return 0;
}
